// -----------------------------------------------------------------------
//  <copyright file="AuthorizationModuleBase.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2024 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2024/12/14 22:12</last-date>
// -----------------------------------------------------------------------

using DaprPlus.AspNetCore;
using DaprPlus.Authorization.Application;
using DaprPlus.Authorization.AspNetCore;
using DaprPlus.Authorization.Domain;
using DaprPlus.Authorization.OpenIddict;
using DaprPlus.Builder;
using DaprPlus.Identity;

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection.Extensions;


namespace DaprPlus.Authorization;

public abstract class AuthorizationModuleBase<TRole> : AspModuleBase
    where TRole : class, IRole
{
    /// <summary>
    /// 获取 模块级别，级别越小越先启动
    /// </summary>
    public override ModuleLevel Level => ModuleLevel.Framework;

    /// <summary>
    /// 获取 模块启动顺序，模块启动的顺序按级别启动，同一级别内部再按此顺序启动
    /// 级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为>0的顺序值
    /// </summary>
    public override int Order => 3;

    /// <summary>
    /// 将模块服务添加到依赖注入服务容器中
    /// </summary>
    /// <param name="services">依赖注入服务容器</param>
    /// <returns></returns>
    public override IServiceCollection AddServices(IServiceCollection services)
    {
        services.AddOpenIddictValidation();

        services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(AuthorizationModuleBase<TRole>).Assembly));
        services.TryAddScoped<IResourceService, ResourceService>();
        services.TryAddScoped<IResourceSynchronizer, ResourceSynchronizer>();
        services.TryAddSingleton<IAuthorizationCache, AuthorizationCache>();
        services.AddSingleton<IDataAuthorizationService, DataAuthorizationService>();

        services.TryAddScoped<ITopAdminRoleService, TopAdminRoleService<TRole>>();
        services.TryAddScoped<IRoleNameResolver, RoleNameResolver<TRole>>();

        services.TryAddKeyedSingleton<IResourceExtractor, EntityResourceExtractor>(ResourceType.Entity);

        services.TryAddKeyedScoped<IAuthorizationService, EntityAuthorizationService>(ResourceType.Entity);
        
        return base.AddServices(services);
    }

    /// <summary>
    /// 应用AspNetCore的服务业务
    /// </summary>
    /// <param name="app">Web应用程序</param>
    public override async Task UseModule(WebApplication app)
    {
        var provider = app.Services;

        app.UseAuthentication();
        app.UseTokenParsing();
        app.UseAuthorization();

        var resourceTypes = new[] { ResourceType.Entity };
        var serviceName = provider.GetServiceName();
        foreach (var resourceType in resourceTypes)
        {
            var extractor = provider.GetKeyedService<IResourceExtractor>(resourceType);
            if (extractor != null)
            {
                await extractor.ExtractAsync(serviceName);
            }
        }

        var authCache = provider.GetRequiredService<IAuthorizationCache>();
        await authCache.BuildResourceCache();
        await authCache.BuildResourceAuthorizationCache();

        IsEnabled = true;
    }
}
